package com.kotlin.base.http

import android.annotation.SuppressLint
import android.content.Context
import cn.yzhg.lib.http.ApiService
import cn.yzhg.lib.http.HttpConstant
import cn.yzhg.lib.http.tools.HttpCacheInterceptor
import cn.yzhg.lib.http.tools.ResponseLogInterceptor
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import io.reactivex.Observable
import okhttp3.*
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.io.File
import java.util.HashMap
import java.util.concurrent.TimeUnit

/**
 * 类 名: YHttp
 * 作 者: yzhg
 * 创 建: 2018/11/16 0016
 * 版 本: 1.0
 * 历 史: (版本) 作者 时间 注释
 * 描 述:
 */
class YHttp {

    companion object {

        @SuppressLint("StaticFieldLeak")
        private var context: Context? = null


        fun init(context: Context) {
            Companion.context = context
        }

        @SuppressLint("StaticFieldLeak")
        private var yHttp: YHttp? = null
        /*双重锁单利模式*/
        val instance: YHttp by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { YHttp() }
    }


    /*
     * 作 者: yzhg
     * 历 史: (版本) 1.0
     * 描 述: 总连接
     */
    private var BASE_URL: String? = ""

    /*
     * 作 者: yzhg
     * 历 史: (版本) 1.0
     * 描 述: 创建 读取时间和连接时间  默认30秒
     */
    private var readTimeOut: Long = 0
    private var connectTimeOut: Long = 0

    /*
     * 作 者: yzhg
     * 历 史: (版本) 1.0
     * 描 述: 设置缓存目录,以及缓存时间(默认24个小时)
     */
    private var cachePath: String? = ""
    // private long cacheTime = 1024 * 1024 * 100;
    private var cacheTime: Long = 0

    /**
     * 作 者: yzhg
     * 历 史: (版本) 1.0
     * 描 述: YHttp 构造方法 ,  在这里复制初始化值
     */
    private fun YHttp() {
        this.BASE_URL = HttpConstant.HTTP_BASE_URL
        this.readTimeOut = HttpConstant.HTTP_READ_TIME_OUT
        this.connectTimeOut = HttpConstant.HTTP_CONNECT_TIME_OUT
        this.cachePath = HttpConstant.HTTP_CACHE_PATH
        this.cacheTime = HttpConstant.HTTP_CACHE_TIME
    }

    /**
     * 作 者: yzhg
     * 历 史: (版本) 1.0
     * 描 述: 处理网络请求结果,返回解析好的对象给主线程  post请求
     *
     * @param urlName  网络请求连接
     * @param paramMap 网络请求参数
     */
    /*    public <T> void requestPostRx(Observer<T> subscriber, Function<String, T> mapper, String urlName, Map<String, Object> paramMap) {
        Observable<T> observable = createRetrofit().create(ApiService.class).postRx(urlName, paramMap).map(new ResponseResultMapper()).map(mapper);
        toSubscribe(observable, subscriber, true);
    }*/
    fun requestPostRx(urlName: String, paramMap: Map<String, String>): Observable<ResponseBody> {
        return createRetrofit().create(ApiService::class.java).postRx(urlName, paramMap)
        // toSubscribe(observable, subscriber, true);
    }

    /**
     * 作 者: yzhg
     * 历 史: (版本) 1.0
     * 描 述: 处理网络请求结果,返回解析好的对象给主线程  get请求
     *
     * @param urlName  网络请求连接
     * @param paramMap 网络请求参数
     */
    fun requestGetRx(urlName: String, paramMap: Map<String, String>): Observable<ResponseBody> {
        return createRetrofit().create(ApiService::class.java).getRx(urlName, paramMap)
    }

    /**
     * 作 者: yzhg
     * 历 史: (版本) 1.0
     * 描 述: 用户上传头像
     *
     * @param urlName 网络请求连接
     * @param outFile 图片File
     */
    fun uploadImage(urlName: String, outFile: File): Observable<ResponseBody> {
        val requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), outFile)
        val body = MultipartBody.Part.createFormData("image", outFile.name, requestBody)
        return createRetrofit().create(ApiService::class.java).uploadImage(urlName, body)
    }

    /**
     * 作 者: yzhg
     * 历 史: (版本) 1.0
     * 描 述: 创建OkHttpClient
     */
    private fun createRetrofit(): Retrofit {
        val gson: Gson = GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").serializeNulls().create()
        return Retrofit.Builder()
                .baseUrl(BASE_URL!!)
                .client(getOkHttpClient())
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build()
    }

    /**
     * 作 者: yzhg
     * 历 史: (版本) 1.0
     * 描 述: 创建OkHttpClient
     */
    private fun getOkHttpClient(): OkHttpClient {
        val cacheFile = File(context!!.cacheDir, cachePath)
        val cache = Cache(cacheFile, cacheTime)
        val build = OkHttpClient.Builder()
        build.addInterceptor(ResponseLogInterceptor())
        //  build.addInterceptor(AppendHeadParamInterceptor())
        //  build.addInterceptor(TokenInterceptor())
        build.addNetworkInterceptor(HttpCacheInterceptor())
        build.readTimeout(readTimeOut, TimeUnit.MILLISECONDS)
        build.connectTimeout(connectTimeOut, TimeUnit.MILLISECONDS)
        build.cache(cache)
        return build.build()
    }

    /**
     * 作 者: yzhg
     * 历 史: (版本) 1.0
     * 描 述: Builder 设计模式打造网络请求框架
     */
    class Builder {
        //总连接
        private var baseUrl = HttpConstant.HTTP_BASE_URL
        //请求参数
        private val params = HashMap<String, Any>()
        //数据类型,默认json类型
        /*
         * 作 者: yzhg
         * 历 史: (版本) 1.0
         * 描 述: 设置超时时间  默认不设置为0
         */
        private var readTimeOut = HttpConstant.HTTP_READ_TIME_OUT
        private var connectTimeOut = HttpConstant.HTTP_CONNECT_TIME_OUT

        /*
         * 作 者: yzhg
         * 历 史: (版本) 1.0
         * 描 述: 设置缓存目录,以及缓存时间(默认24个小时)
         */
        private var cachePath = HttpConstant.HTTP_CACHE_PATH
        private var cacheTime = HttpConstant.HTTP_CACHE_TIME


        /**
         * 作 者: yzhg
         * 历 史: (版本) 1.0
         * 描 述: 设置  总连接地址
         */
        fun setBaseUrl(baseUrl: String): Builder {
            this.baseUrl = baseUrl
            return this
        }


        /**
         * 作 者: yzhg
         * 历 史: (版本) 1.0
         * 描 述: 设置读取时间
         */
        fun setReadTimeOut(readTimeOut: Long): Builder {
            this.readTimeOut = readTimeOut
            return this
        }

        /**
         * 作 者: yzhg
         * 历 史: (版本) 1.0
         * 描 述: 设置连接超时时间
         */
        fun setConnectTimeOut(connectTimeOut: Long): Builder {
            this.connectTimeOut = connectTimeOut
            return this
        }

        /**
         * 作 者: yzhg
         * 历 史: (版本) 1.0
         * 描 述: 设置网络读取时间和网络超时时间  优先级高
         *
         * @param readTimeOut    网络读取时间
         * @param connectTimeOut 网络超时时间
         */
        fun setReadAndConnectTimeOut(readTimeOut: Long, connectTimeOut: Long): Builder {
            this.readTimeOut = readTimeOut
            this.connectTimeOut = connectTimeOut
            return this
        }

        /**
         * 作 者: yzhg
         * 历 史: (版本) 1.0
         * 描 述: 设置缓存路径 , 设置缓存时间
         *
         * @param cachePath 缓存路径
         * @param cacheTime 缓存时间
         */
        fun setCachePath(cachePath: String, cacheTime: Long): Builder {
            this.cachePath = cachePath
            this.cacheTime = cacheTime
            return this
        }


        /**
         * 作 者: yzhg
         * 历 史: (版本) 1.0
         * 描 述: 给应用赋值
         */
        private fun applyConfig(yHttp: YHttp) {
            if ("" != baseUrl) yHttp.BASE_URL = this.baseUrl
            if (this.readTimeOut != 0L) yHttp.readTimeOut = this.readTimeOut //设置读取时间
            if (this.connectTimeOut != 0L) yHttp.connectTimeOut = this.connectTimeOut  //设置网络连接时间
            if ("" != this.cachePath) yHttp.cachePath = this.cachePath  //设置缓存路径
            if (0L != this.cacheTime) yHttp.cacheTime = this.cacheTime  //设置缓存时间
        }

        fun build(): YHttp {
            val http: YHttp = YHttp()
            applyConfig(http)
            return http
        }
    }

}